//------------------------------------------------------------------------------

#include "diff.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "action.h"
#include "split.h"
#include "util.h"

//------------------------------------------------------------------------------
#define MAX(a,b) ((a)>(b) ? (a) : (b))
//------------------------------------------------------------------------------
void diff(char *text1, char *text2, char **result) {
	char **lignes1, **lignes2;
	int M = split(text1, &lignes1);
	int N = split(text2, &lignes2);
	int i, j;
	int *opt = (int *) malloc((M + 1) * (N + 1) * sizeof(int));

	for (i = M - 1; i >= 0; i--) {
		for (j = N - 1; j >= 0; j--) {
			int idx = j * (M + 1) + i;
			if (!strcmp(lignes1[i], lignes2[j])) {
				opt[idx] = opt[idx + M + 2] + 1;
			} else {
				opt[idx] = MAX(opt[idx + 1], opt[idx + M + 1]);
			}
		}
	}

	i = j = 0;
	while (i < M && j < N) {
		int idx = j * (M + 1) + i;
		if (!strcmp(lignes1[i], lignes2[j])) {
			i++;
			j++;
		} else if (opt[idx + 1] >= opt[idx + M + 1]) {
			addAction(etaDelete, i++);
		} else {
			addAction(etaAdd, j++);
		}
	}

	while (i < M || j < N) {
		if (i == M) {
			addAction(etaAdd, j++);
		} else if (j == N) {
			addAction(etaDelete, i++);
		}
	}

	computeActions(lignes2, result);

	freeActions();
	free(opt);

	if (M != 0) {
		free(lignes1[0]);
		free(lignes1);
	}
	if (N != 0) {
		free(lignes2[0]);
		free(lignes2);
	}
}
//------------------------------------------------------------------------------
void merge(char *source, char *patch, char **result) {
	char **sourceLignes;
	char **patchLignes;
	char **mergedLignes;
	int nbSourceLignes = split(source, &sourceLignes);
	int nbMergedLignes = nbSourceLignes;
	int nbPatchLignes = split(patch, &patchLignes);
	int i = 0;
	int resultSize = 0;

	mergedLignes = (char **) calloc(nbMergedLignes, sizeof(char **));
	memcpy(mergedLignes, sourceLignes, nbMergedLignes * sizeof(char **));

	while (i < nbPatchLignes) {
		ETypeAction action;
		int start, size, idx;
		sscanf(patchLignes[i], "%c %d,%d", (char *) &action, &start, &size);

		switch ((char) action) {
		case etaAdd:
			mergedLignes = realloc(mergedLignes,
					(nbMergedLignes + size) * sizeof(char **));
			for (idx = nbMergedLignes + size - 1; idx >= start + size; idx--) {
				mergedLignes[idx] = mergedLignes[idx - size];
			}

			for (idx = 0; idx < size; idx++) {
				mergedLignes[start + idx] = patchLignes[i + idx + 1] + 2;
			}
			nbMergedLignes += size;
			i += size + 1;
			break;
		case etaDelete:
			for (idx = start; idx < nbMergedLignes - size; idx++) {
				mergedLignes[idx] = mergedLignes[idx + size];
			}
			nbMergedLignes -= size;
			mergedLignes = realloc(mergedLignes,
					nbMergedLignes * sizeof(char **));
			i++;
			break;
		}
	}

	for (i = 0; i < nbMergedLignes; i++) {
		if (i != 0) {
			resultSize = reallocExCpy(result, resultSize, "\n");
		}
		resultSize = reallocExCpy(result, resultSize, mergedLignes[i]);
	}

	if (nbSourceLignes != 0) {
		free(sourceLignes[0]);
		free(sourceLignes);
	}
	if (nbPatchLignes != 0) {
		free(patchLignes[0]);
		free(patchLignes);
	}
	if (nbMergedLignes != 0) {
		free(mergedLignes);
	}
}
//------------------------------------------------------------------------------
